<?php

namespace OAuth2\Example\Server\Authorize;

class Handler {
    
    protected $_oauth;
    protected $_options;
    
    function __construct(\OAuth2\Server $oauth, $options = array())
    {
        $this->setOauth($oauth);
        $this->setOptions($options);
    }
    
    /**
     * Oauth getter
     * @return type 
     */
     public function getOauth()      {
         return $this->_oauth;
     }

     /**
      * Oauth setter
      * 
      * @param type $oauth 
      */
     public function setOauth(\OAuth2\Server $oauth)
     {
         $this->_oauth = $oauth;
     }
     
     /**
      * Options getter
      *
      * @return array
      */
     public function getOptions() 
     {
         return $this->_options;
     }

     /**
      * Options setter
      *
      * @param array $options 
      */
     public function setOptions($options)
     {
         $this->_options = $options;
     }

    
    /**
    * Send out error message in JSON.
    *
    * @param $http_status_code
    *   HTTP status code message as predefined.
    * @param $error
    *   A single error code.
    * @param $error_description
    *   (optional) A human-readable text providing additional information,
    *   used to assist in the understanding and resolution of the error
    *   occurred.
    * @param $error_uri
    *   (optional) A URI identifying a human-readable web page with
    *   information about the error, used to provide the end-user with
    *   additional information about the error.
    *
    * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3
    *
    * @ingroup oauth2_error
    */
    public function errorJsonResponse($http_status_code, $error, $error_description = NULL, $error_uri = NULL) {
        $result['error'] = $error;
        $options = $this->getOptions();
        $displayErrors = isset($options['display_errors']) && $options['display_errors'] === true;
        
        if ($displayErrors && $error_description)
          $result["error_description"] = $error_description;

        if ($displayErrors && $error_uri)
          $result["error_uri"] = $error_uri;

        header("HTTP/1.1 " . $http_status_code);
        $this->sendJsonHeaders();
        echo json_encode($result);


        exit;
    }


    /**
    * Send out HTTP headers for JSON.
    *
    * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.2
    * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3
    *
    * @ingroup oauth2_section_4
    */
    public function sendJsonHeaders() {
        header("Content-Type: application/json");
        header("Cache-Control: no-store");
    }
    
    public function handleAuthorizationRequest() {
        try {
            $rt = $this->getOauth()->finishClientAuthorization($_POST['client_id'], $_POST['redirect_uri'], $_POST['response_type'], $_POST['scope'], $_POST['state']) ;
            $this->getOauth()->doRedirectUriCallback($rt);
        } catch(OAuth2\Server\Exception $excption) {
            $this->errorJsonResponse($excption->getHttpStatusCode(), $excption->getError(), $excption->getMessage(), $excption->getErrorUri());
        }
    }
    
  /**
   * Pull the authorization request data out of the HTTP request.
   *
   * @return
   *   The authorization parameters so the authorization server can prompt
   *   the user for approval if valid.
   *
   * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3
   *
   * @ingroup oauth2_section_3
   */
    function getAuthorizeParams() {

        $filters = array(
          "client_id" => array("filter" => FILTER_VALIDATE_REGEXP, "options" => array("regexp" => OAUTH2_CLIENT_ID_REGEXP), "flags" => FILTER_REQUIRE_SCALAR),
          "response_type" => array("filter" => FILTER_VALIDATE_REGEXP, "options" => array("regexp" => OAUTH2_AUTH_RESPONSE_TYPE_REGEXP), "flags" => FILTER_REQUIRE_SCALAR),
          "redirect_uri" => array("filter" => FILTER_SANITIZE_URL),
          "state" => array("flags" => FILTER_REQUIRE_SCALAR),
          "scope" => array("flags" => FILTER_REQUIRE_SCALAR),
        );

        $input = filter_input_array(INPUT_GET, $filters);

        // Make sure a valid client id was supplied
        if (!$input["client_id"]) {
          if ($input["redirect_uri"])
            return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_INVALID_CLIENT, NULL, NULL, $input["state"]);

          $this->errorJsonResponse(OAUTH2_HTTP_FOUND, OAUTH2_ERROR_INVALID_CLIENT); // We don't have a good URI to use
        }

        // redirect_uri is not required if already established via other channels
        // check an existing redirect URI against the one supplied
        $redirect_uri = $this->getOauth()->getRedirectUri($input["client_id"]);

        // At least one of: existing redirect URI or input redirect URI must be specified
        if (!$redirect_uri && !$input["redirect_uri"])
          $this->errorJsonResponse(OAUTH2_HTTP_FOUND, OAUTH2_ERROR_INVALID_REQUEST);

        // getRedirectUri() should return FALSE if the given client ID is invalid
        // this probably saves us from making a separgate db call, and simplifies the method set
        if ($redirect_uri === FALSE)
          return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_INVALID_CLIENT, NULL, NULL, $input["state"]);

        // If there's an existing uri and one from input, verify that they match
        if ($redirect_uri && $input["redirect_uri"]) {
          // Ensure that the input uri starts with the stored uri
          if (strcasecmp(substr($input["redirect_uri"], 0, strlen($redirect_uri)), $redirect_uri) !== 0)
            return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_REDIRECT_URI_MISMATCH, NULL, NULL, $input["state"]);
        }
        elseif ($redirect_uri) { // They did not provide a uri from input, so use the stored one
          $input["redirect_uri"] = $redirect_uri;
        }

        // type and client_id are required
        if (!$input["response_type"])
          return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_INVALID_REQUEST, 'Invalid response type.', NULL, $input["state"]);

        // Check requested auth response type against the list of supported types
        if (array_search($input["response_type"], $this->getOauth()->getSupportedAuthResponseTypes()) === FALSE)
          return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_UNSUPPORTED_RESPONSE_TYPE, NULL, NULL, $input["state"]);

        // Restrict clients to certain authorization response types
        if ($this->getOauth()->checkRestrictedAuthResponseType($input["client_id"], $input["response_type"]) === FALSE)
          return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_UNAUTHORIZED_CLIENT, NULL, NULL, $input["state"]);

        // Validate that the requested scope is supported
        if ($input["scope"] && !$this->getOauth()->checkScope($input["scope"], $this->getOauth()->getSupportedScopes()))
          return $this->getOauth()->errorDoRedirectUriCallback($input["redirect_uri"], OAUTH2_ERROR_INVALID_SCOPE, NULL, NULL, $input["state"]);
    
        return $input;
      }
}